import { GM_getValue, GM_setValue } from "tm";

interface Position {
  x: number;
  y: number;
}

const initPosition: Position = { x: 10, y: 10 };

let oOverflow = "initial",
  relationPosition: Position = initPosition,
  savedPos: Position = initPosition,
  moving = false,
  mouseMoving = false;

const savedPosValue = JSON.parse(
  (GM_getValue("vcs_fab_pos", JSON.stringify(initPosition)) as
    | string
    | undefined) ?? JSON.stringify(initPosition),
) as Position;

if (typeof savedPosValue.x == "number" && typeof savedPosValue.y == "number")
  savedPos = savedPosValue;
// http://www.quirksmode.org/js/findpos.html
function findPos(element: HTMLElement | null): Position {
  const pos: Position = { x: 0, y: 0 };
  if (element) {
    do {
      pos.x += element.offsetLeft;
      pos.y += element.offsetTop;
    } while ((element = element.offsetParent as HTMLElement | null));
  }
  return pos;
}

function buttonMoveStart(
  event_: MouseEvent | TouchEvent,
  element: HTMLElement,
) {
  relationPosition =
    event_ instanceof MouseEvent
      ? {
          x: event_.pageX - findPos(element).x,
          y: event_.pageY - findPos(element).y,
        }
      : {
          x: event_.touches[0].pageX - findPos(element).x,
          y: event_.touches[0].pageY - findPos(element).y,
        };
  moving = true;
  mouseMoving = false;
  document.documentElement.style.overflow = "hidden";
}

function buttonMoving(event_: MouseEvent | TouchEvent, element: HTMLElement) {
  if (event_ instanceof MouseEvent) {
    element.style.left = String(event_.pageX - relationPosition.x) + "px";
    element.style.top = String(event_.pageY - relationPosition.y) + "px";
  } else {
    element.style.left =
      String(event_.touches[0].pageX - relationPosition.x) + "px";
    element.style.top =
      String(event_.touches[0].pageY - relationPosition.y) + "px";
  }
}

function buttonMoveEnd(element: HTMLElement) {
  GM_setValue(
    "vcs_fab_pos",
    JSON.stringify({
      x: Number.parseInt(getComputedStyle(element).left),
      y: Number.parseInt(getComputedStyle(element).top),
    }),
  );
  moving = false;
  document.documentElement.style.overflow = oOverflow;
}

export function showButton(callback: () => Promise<void>) {
  oOverflow = getComputedStyle(document.documentElement).overflow;
  const fab = document.createElement("div");
  fab.id = "vCatchBtn";
  fab.className = "mdc-touch-target-wrapper";
  fab.innerHTML = `
  <button class="mdc-fab mdc-fab--mini mdc-fab--touch">
    <div class="mdc-fab__ripple"></div>
    <div class="mdc-fab__focus-ring"></div>
    <span class="mdc-fab__icon" id="showSwalIcon"></span>
    <div class="mdc-fab__touch"></div>
  </button>`;

  fab.addEventListener("click", () => {
    if (mouseMoving) {
      mouseMoving = false;
    } else {
      callback()
        .then(() => {
          mouseMoving = false;
        })
        .catch(() => {
          mouseMoving = false;
        });
    }
  });
  fab.addEventListener("mousedown", (event_) => {
    buttonMoveStart(event_, fab);
  });
  fab.addEventListener("mousemove", (event_) => {
    if (moving) {
      buttonMoving(event_, fab);
      mouseMoving = true;
    }
  });
  fab.addEventListener("mouseup", () => {
    buttonMoveEnd(fab);
  });
  fab.addEventListener("touchstart", (event_) => {
    buttonMoveStart(event_, fab);
  });
  fab.addEventListener("touchmove", (event_) => {
    if (moving) buttonMoving(event_, fab);
  });
  fab.addEventListener("touchend", () => {
    buttonMoveEnd(fab);
  });
  fab.addEventListener("touchcancel", () => {
    buttonMoveEnd(fab);
  });
  fab.style.top = String(savedPos.y) + "px";
  fab.style.left = String(savedPos.x) + "px";
  document.documentElement.append(fab);
}
